use std::ops::{Range, RangeInclusive};
use std::u8;

use num::Complex;

use crate::gen_title;

/// ### 整形溢出
pub fn ch2_2_1() {
    gen_title("ch2_2_1", 18);
    let a: u8 = 255;
    let b = a.wrapping_add(20);
    println!("{}", b);
}

/// ### 浮点类型
pub fn ch2_2_2() {
    gen_title("ch2_2_2", 18);
    let x = 2.0;
    let y: f32 = 3.0;
    println!("x = {}, y = {}", x, y);
}

/// 浮点类型不能期望存在绝对相等性 需要小心
pub fn ch2_2_3() {
    gen_title("ch2_2_3", 18);

    let abc: (f32, f32, f32) = (0.1, 0.2, 0.3);
    let xyz: (f64, f64, f64) = (0.1, 0.2, 0.3);

    println!("abc (f32)");
    println!("    0.1 + 0.2: {:x}", (abc.0 + abc.1).to_bits());
    println!("          0.3: {:x}", (abc.2).to_bits());

    println!("xyz (f64)");
    println!("    0.1 + 0.2: {:x}", (xyz.0 + xyz.1).to_bits());
    println!("          0.3: {:x}", (xyz.2).to_bits());

    assert_eq!(abc.0 + abc.1, abc.2);
    // assert_eq!(xyz.0 + xyz.1, xyz.2); 不能运行
}

/// is_nan() - NaN
pub fn ch2_2_4() {
    gen_title("ch2_2_4", 18);

    let x = (-42.0_f32).sqrt();
    if x.is_nan() {
        println!("未定义的数学行为");
    }
}

/// ### 数字运算
pub fn ch2_2_5() {
    gen_title("ch2_2_5", 18);
    let sum = 5 + 10;
    let difference = 95.5 - 4.3;
    let product = 4 + 30;
    let quotient = 56.7 / 32.2;
    let remainder = 43 % 5;

    println!(
        "sum: {}, difference: {}, product: {}, quotient: {}, remainder: {}",
        sum, difference, product, quotient, remainder
    );
}

pub fn ch2_2_6() {
    gen_title("ch2_2_6", 18);

    // 编译器会进行自动推导，给予twenty i32的类型
    let twenty = 20;
    // 类型标注a
    let twenty_one: i32 = 21;
    // 通过类型后缀的方式进行类型标注：22是i32类型
    let twenty_two = 22i32;

    // 只有同样类型，才能运算
    let addition = twenty + twenty_one + twenty_two;
    println!(
        "{} + {} + {} = {}",
        twenty, twenty_one, twenty_two, addition
    );

    // 对于较长的数字，可以用_进行分割，提升可读性
    let one_million: i64 = 1_000_000;
    println!("{}", one_million.pow(2));

    // 定义一个f32数组，其中42.0会自动被推导为f32类型
    let forty_twos = [42.0, 42f32, 42.0_f32];

    // 打印数组中第一个值，并控制小数位为2位
    println!("{:.2}", forty_twos[0]);
}

/// ### 位运算
pub fn ch2_2_7() {
    gen_title("ch2_2_7", 18);
    // 二进制00000010
    let a: i32 = 2;
    // 二进制00000011
    let b: i32 = 3;

    println!("a & b = {}", a & b);
    println!("a | b = {}", a | b);
    println!("a ^ b = {}", a ^ b);
    println!("!a = {}", !a);
    println!("(a << b) = {}", a << b);
    println!("(a >> b) = {}", a >> b);

    let mut a = a;
    a <<= b;
    println!("a <<= b = {}", a);
}

/// ### 序列
pub fn ch2_2_8() {
    gen_title("ch2_2_8", 18);
    for i in 1..=5 {
        println!("{}", i);
    }

    for i in 'a'..='z' {
        println!("{}", i);
    }
}

/// ### 有理数和复数
pub fn ch2_2_9() {
    gen_title("ch2_2_9", 18);

    let a = Complex { re: 2.1, im: -1.2 };
    let b = Complex::new(11.1, 22.2);
    let result = a + b;

    println!("{} + {}i", result.re, result.im);
}

/// ### 整数
pub fn ch2_2_pra_1() {
    gen_title("ch2_2_pra_1", 18);

    let x: i32 = 5;
    let mut y: i32 = 5;

    y = x;
    let z = 10;

    println!("x = {}, y = {}, z = {}", x, y, z);
}

/// ### 整数
pub fn ch2_2_pra_2() {
    gen_title("ch2_2_pra_2", 18);

    let v: u16 = 38_u8 as u16;
    println!("{}", v);
}

/// ### 整数
pub fn ch2_2_pra_3() {
    gen_title("ch2_2_pra_3", 18);

    let x = 5;
    assert_eq!("i32".to_string(), type_of(&x));

    println!("{}", type_of(&x));
}

fn type_of<T>(_: &T) -> String {
    format!("{}", std::any::type_name::<T>())
}

/// ### 整数
pub fn ch2_2_pra_4() {
    gen_title("ch2_2_pra_4", 18);

    assert_eq!(i8::MAX, 127);
    assert_eq!(u8::MAX, 255);

    println!("{}, {}", i8::MAX, u8::MAX);
}

/// ### 整数
pub fn ch2_2_pra_5() {
    gen_title("ch2_2_pra_5", 18);

    let v1 = 251_u8 as u16 + 8_u16;
    let v2 = u16::checked_add(251, 8).unwrap();
    println!("{}, {}", v1, v2);
}

/// ### 整数
pub fn ch2_2_pra_6() {
    gen_title("ch2_2_pra_6", 18);

    let v = 1_024 + 0xff + 0o77 + 0b1111_1111;
    assert_eq!(v, 1597);

    println!("{}", v);
}

/// ### 浮点数
pub fn ch2_2_pra_7() {
    gen_title("ch2_2_pra_7", 18);

    let x = 1_000.000_1;
    let y: f32 = 0.12;
    let z = 0.01_f64;

    println!("{}, {}, {}", x, y, z);
}

/// ### 浮点数
pub fn ch2_2_pra_8() {
    gen_title("ch2_2_pra_8", 18);

    assert_eq!(0.1_f32 + 0.2_f32, 0.3_f32);
    println!("{}", 0.1_f32 + 0.2_f32);
}

pub fn ch2_2_pra_9() {
    gen_title("ch2_2_pra_9", 18);

    let mut sum = 0;
    for i in -3..2 {
        sum += i;
    }

    assert_eq!(sum, -5);
    println!("{}", sum);

    for c in 'a'..'z' {
        println!("{}", c);
    }
}

pub fn ch2_2_pra_10() {
    gen_title("ch2_2_pra_10", 18);

    assert_eq!((1..5), Range { start: 1, end: 5 });
    assert_eq!((1..=5), RangeInclusive::new(1, 5));

    println!("{:?}", (1..5));
    println!("{:?}", (1..=5));
}

pub fn ch2_2_pra_11() {
    gen_title("ch2_2_pra_11", 18);

    assert_eq!(1u32 + 2, 3);
    println!("{}", 1u32 + 2);

    assert_eq!(1i32 - 2, -1);
    println!("{}", 1i32 - 2);

    assert_eq!(1i8 - 2, -1);
    println!("{}", 1i8 - 2);

    assert_eq!(3 * 50, 150);
    println!("{}", 3 * 50);

    assert_eq!(9.6_f32 / 3.2_f32, 3.0_f32);
    println!("{}", 9.6 / 3.2);

    assert_eq!(24 % 5, 4);
    println!("{}", 24 % 5);

    assert_eq!(true && false, false);
    println!("{}", true && false);

    assert_eq!(true || false, true);
    println!("{}", true || false);

    assert_eq!(!true, false);
    println!("{}", !true);

    println!("0011 AND 0101 is {:04b}", 0b0011u32 & 0b0101);
    println!("0011 OR 0101 is {:04b}", 0b0011u32 | 0b0101);
    println!("0011 XOR 0101 is {:04b}", 0b0011u32 ^ 0b0101);
    println!("1 << 5 is {}", 1u32 << 5);
    println!("0x80 >> 2 is 0x{:x}", 0x80u32 >> 2);
}
